package com.cenxi.utils;


import com.cenxi.common.base.BaseTree;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

/**
 * 树形转换
 * @author dijia
 */
public class TreeUtil {

    private TreeUtil(){
        throw new IllegalStateException("禁止实例化");
    }

    /**
     * 获取全局树
     * @param source
     * @return
     * @param <T>
     */
    public static <T extends BaseTree> List<T> parseTree(List<T> source){
        if (CollectionUtils.isEmpty(source)){
            return Collections.emptyList();
        }
        List<T> topNode = source.stream().filter(s -> isNullOrEmpty(s.getParentId())).collect(Collectors.toList());

        List<T> childrenNode = source.stream().filter(s -> !isNullOrEmpty(s.getParentId())).collect(Collectors.toList());
        // 如果子节点中存在parent不在source中的节点，即将其当做顶节点，以生成树
        List<Object> sourceIds = source.stream().map(BaseTree::getId).collect(toList());
        for(T node : source) {
            if (!isNullOrEmpty(node.getParentId()) && !sourceIds.contains(node.getParentId())) {
                topNode.add(node);
                childrenNode.remove(node);
            }
        }
        if (CollectionUtils.isEmpty(childrenNode)) {
            return topNode;
        }

        return getTree(topNode,childrenNode);

    }

    /**
     * 获取某一棵树
     * @param source
     * @param top
     * @return
     * @param <T>
     */
    public static <T extends BaseTree> T parseTree(List<T> source,T top){
        if (CollectionUtils.isEmpty(source)){
            return null;
        }
        List<T> childrenNode = source.stream().filter(s -> !isNullOrEmpty(s.getParentId())).collect(Collectors.toList());
        return getTree(top,childrenNode);

    }

    private static  <T extends BaseTree>  T getTree(T topNode ,List<T> children){
        if (!CollectionUtils.isEmpty(children)){
            HashMap<Object,Object> map = Maps.newHashMapWithExpectedSize(children.size());
             getChild(topNode,map,children);
            return topNode;
        }
        return topNode;
    }

    private static  <T extends BaseTree>  List<T> getTree( List<T> topNode ,List<T> children){
        if (!CollectionUtils.isEmpty(children)){
            HashMap<Object,Object> map = Maps.newHashMapWithExpectedSize(children.size());
            topNode.forEach(v -> getChild(v,map,children));
            return topNode;
        }
        return topNode;
    }

    private static  <T extends BaseTree> void getChild(T t,Map<Object,Object> map,List<T> child){
        List<T> childList = Lists.newArrayList();
        child.stream().filter(c -> !map.containsKey(c.getId()))
                .filter(c -> c.getParentId().equals(t.getId()))
                .forEach(c -> {
                    map.put(c.getId(),c.getParentId());
                    getChild(c,map,child);
                    childList.add(c);
                });

        t.setChildren(!CollectionUtils.isEmpty(childList)?childList:null);
    }


    public static boolean isNullOrEmpty(Object obj) {
        if (obj == null) {
            return true;
        }
        if (obj instanceof Integer){
            return (Integer) obj == 0;
        }
        if (obj instanceof CharSequence) {
            return ((CharSequence) obj).length() == 0;
        }
        if (obj instanceof Collection) {
            return ((Collection) obj).isEmpty();
        }
        if (obj instanceof Map) {
            return ((Map) obj).isEmpty();
        }
        if (obj instanceof Object[]) {
            Object[] object = (Object[]) obj;
            if (object.length == 0) {
                return true;
            }
            boolean empty = true;
            for (Object o : object) {
                if (!isNullOrEmpty(o)) {
                    empty = false;
                    break;
                }
            }
            return empty;
        }
        return false;
    }

}
